package app.htby.utils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson.JSON;

import app.entity.IOTPBean;
import app.entity.IOTPBody;


/**
 * @ClassName: IotpBodyUtils
 * @Description: 协议消息体的工具类
 * @author 周西栋
 * @date 2018年5月16日
 *
 */
public class IotpBodyUtils {
	
	IOTPBean iotpBean = new IOTPBean();
	
	/**
	 * 消息体字节数组管理器
	 * byte转IOTPBean时使用（多批时）
	 */
	List<byte[]> body_byte_list = new ArrayList<byte[]>();
	
	/********************************************************** 解析byte数组 **********************************************************/
	
	/**
	 * @Title: toIotpBean
	 * @Description: 将byte[]转成IOTPBean 对象
	 * @param @param iotp_bytes
	 * @param @return    参数
	 * @return Code    返回类型
	 * @throws
	 */
	public Code toIotpBean(byte[] iotp_bytes){
		IOTPBean iotp = new IOTPBean();
		Code code = new Code();
		// 没有消息体时byte[]长度是162，消息体为空时byte[]长度是166
		if(iotp_bytes.length < 166){
			return checkResult(code,"0001");
		}else if(iotp_bytes.length > 8354){
			System.out.println("iotp_bytes" + Arrays.toString(iotp_bytes));
			
			return checkResult(code,"0002");
		}else {
			// 协议头
			try {
				iotp.setTag(byteArrayToInteger(iotp_bytes,0,2));
				if(iotp.getTag() != 0x1011){
					return checkResult(code,"0101");
				}
			} catch (Exception e) {
				return checkResult(code,"0101");
			}
			//协议尾
			try {
				iotp.setEnd(byteArrayToInteger(iotp_bytes,iotp_bytes.length-2,2));
				if(iotp.getEnd() != 0x1213){
					return checkResult(code,"0102");
				}
			} catch (Exception e) {
				return checkResult(code,"0102");
			}
			//消息体长度
			try {
				iotp.setBody_len(byteArrayToInteger(iotp_bytes,156,4));
				if(iotp.getBody_len() < 4){
					return checkResult(code,"0103");
				}
				if(iotp.getBody_len() > 8192){
					return checkResult(code,"0112");
				}
			} catch (Exception e) {
				return checkResult(code,"0111");
			}
			//协议类型
			try {
				iotp.setType(byteArrayToInteger(iotp_bytes,2,2));
				if(iotp.getType() < 0 || iotp.getType() > 20){
					return checkResult(code,"0104");
				}
			} catch (Exception e) {
				return checkResult(code,"0104");
			}
			//源id
			try {
				iotp.setSource_id(byteArrayToInteger(iotp_bytes,4,4));
				if(iotp.getSource_id() < 0){
					return checkResult(code,"0105");
				}
			} catch (Exception e) {
				return checkResult(code,"0105");
			}
			//源类型
			try {
				iotp.setSource_type(byteArrayToInteger(iotp_bytes,8,4));
				if(iotp.getSource_type() < 0){
					return checkResult(code,"0106");
				}
			} catch (Exception e) {
				return checkResult(code,"0106");
			}
			//协议序列号
			try {
				iotp.setSequence_id(byteArrayToInteger(iotp_bytes,12,4));
				if(iotp.getSequence_id() < 0){
					return checkResult(code,"0107");
				}
			} catch (Exception e) {
				return checkResult(code,"0107");
			}
			//协议子序列号
			try {
				iotp.setSequence_sub_id(byteArrayToInteger(iotp_bytes,16,4));
				if(iotp.getSequence_sub_id() < -1){
					return checkResult(code,"0108");
				}
			} catch (Exception e) {
				return checkResult(code,"0108");
			}
			//协议包生成时间
			try {
				long currenttime = new Date().getTime();
				long creattime = 0L;
				try {
					creattime = byteArrayToLong(iotp_bytes,20,8);
				} catch (Exception e) {
					e.printStackTrace();
				}
				iotp.setDate_time(new Date(creattime));
				if(creattime >= currenttime || creattime < 1526433917088L){
					return checkResult(code,"0109");
				}
			} catch (Exception e) {
				return checkResult(code,"0109");
			}
			//授权码
			try {
				iotp.setLicense(byteArrayToString(iotp_bytes,28,128));
				if("".equals(iotp.getLicense()) || iotp.getLicense() == null){
					return checkResult(code,"0110");
				}
			} catch (Exception e) {
				return checkResult(code,"0110");
			}
			//消息体
			try {
				if(iotp.getSequence_sub_id() == 0){
					iotp.setBody(JSON.parseObject(byteArrayToString(iotp_bytes,160,iotp.getBody_len()), IOTPBody.class));
				}else if(iotp.getSequence_sub_id() == -1){
					// 将最后一个分段的字节数组添加到消息体字节数组管理器中
					body_byte_list.add(getNewByteArray(iotp_bytes, 160,iotp.getBody_len()));
					// 将消息体字节数组管理器中的所有数组整理，并转成IOTPBody对象
					iotp.setBody(byteArrayToIotpBody());
				}else{
					// 将分段的字节数组添加到消息体字节数组管理器中
					body_byte_list.add(getNewByteArray(iotp_bytes, 160,iotp.getBody_len()));//iotp.getBody_len()等于8192
				}
			} catch (Exception e) {
				return checkResult(code,"0103");
			}
			iotpBean = iotp;
			return checkResult(code,"0");
		}
	}
	
	public IOTPBean getIotpBean() {
		return iotpBean;
	}

	public void setIotpBean(IOTPBean iotpBean) {
		this.iotpBean = iotpBean;
	}

	/**
	 * @Title: checkResult
	 * @Description: 处理统一编码结果
	 * @param @param code
	 * @param @param codeNum
	 * @param @return    参数
	 * @return Code    返回类型
	 * @throws
	 */
	private Code checkResult(Code code,String codeNum){
		code.setCode(codeNum);
		code.setMessage(CodeConfig.getInstance().CODE_MAP.get(code.getCode()));
		return code;
	}

	/**
	 * @Title: getNewByteArray
	 * @Description: 将byte数组，从下标为start开始，到下标为（start+step-1）之间的元素转成String字符串
	 * 如果（start+step-1）超出了a的长度，则超出部分将丢弃。
	 * 如果start起始位置超出a的长度，则按取模数为下标起始位置
	 * 如果start起始位置是负数，则按0为下标起始位置
	 * @param @param b
	 * @param @param start 下标起始位置
	 * @param @param step 数组自起始位置start往后的元素个数（数组长度）
	 * @param @return    参数
	 * @return byte[]    返回类型
	 * @throws
	 */
	public byte[] getNewByteArray(byte[] a,int start,int step){
		start = start < 0 ? 0: (start > (a.length - 1) ? start % a.length : start);
		step = (start+step-1) > (a.length - 1) ? (a.length - 1) : (start+step-1);
		int b_len = step-start+1;
		byte[] b = new byte[b_len];
		int index = 0;
		while(index < b_len){
			b[index] = a[start+index];
			index++;
		}
		return b;
	}
	
	/**
	 * @Title: byteArrayToInteger
	 * @Description: 将byte数组的一部分转成Integer类型
	 * @param @param a
	 * @param @param start byte数组a的起始位置
	 * @param @param step 需要截取的数组长度
	 * @param @return    参数
	 * @return Integer    返回类型
	 * @throws
	 */
	public Integer byteArrayToInteger(byte[] a,int start,int step){
		byte[] b = getNewByteArray(a,start,step);
		return Hex.byteArrayToIntDesc(b, b.length);
	}
	
	/**
	 * @Title: byteArrayToString
	 * @Description: 将byte数组的一部分转成String类型
	 * @param @param a
	 * @param @param start byte数组a的起始位置
	 * @param @param step 需要截取的数组长度
	 * @param @return    参数
	 * @return String    返回类型
	 * @throws
	 */
	public String byteArrayToString(byte[] a,int start,int step){
		return new String(getNewByteArray(a,start,step));
	}
	
	/**
	 * @Title: byteArrayToLong
	 * @Description: 将byte数组的一部分转成Long类型
	 * @param @param a
	 * @param @param start byte数组a的起始位置
	 * @param @param step 需要截取的数组长度
	 * @param @return    参数
	 * @return String    返回类型
	 * @throws
	 */
	public Long byteArrayToLong(byte[] a,int start,int step){
		return Hex.bytesToLong(getNewByteArray(a,start,step));
	}
	
	/**
	 * @Title: byteArrayToIotpBody
	 * @Description: 将消息体字节数组管理器中的字节数组转成IOTPBody对象
	 * @param @return    参数
	 * @return IOTPBody    返回类型
	 * @throws
	 */
	private IOTPBody byteArrayToIotpBody(){
		if(body_byte_list.size() < 2){
			return null;
		}
		byte[] bodybytes = new byte[((body_byte_list.size() - 1) * 8192) + body_byte_list.get(body_byte_list.size()-1).length];
		for(int i = 0; i < body_byte_list.size(); i++){
			byteArrayAddbyteArray(bodybytes, body_byte_list.get(i), (i * 8192), body_byte_list.get(i).length);
		}
//		System.out.println("--- --- --- --- --- --- --- "+new String(bodybytes));
//		System.out.println(new String(bodybytes).length());
		return JSON.parseObject(new String(bodybytes),IOTPBody.class);
	}
	
	/********************************************************** 解析byte数组 **********************************************************/
	
	/********************************************************** 转成byte数组 **********************************************************/
	
	/**
	 * 转换byte数组使用
	 */
	// 协议标签(字节长度为2)
	byte[] tag_byte = new byte[2];
	// 命令类型(字节长度为2)
	byte[] type_byte = new byte[2];
	// 源ID号(字节长度为4)
	byte[] source_id_byte = new byte[4];
	// 源类型号(字节长度为4)
	byte[] source_type_byte = new byte[4];
	// 协议序列号(字节长度为4)
	byte[] sequence_id_byte = new byte[4];
	// 协议子序列号(字节长度为4)
	byte[] sequence_sub_id_byte = new byte[4];
	// 协议包生成时间(字节长度为8)
	byte[] date_time_byte = new byte[8];
	// 节点授权码(字节长度128)
	byte[] license_byte = new byte[128];
	// 协议体长度(字节长度为4)
	byte[] body_len_byte = new byte[4];
	// 协议消息体
	byte[] body_byte = null;
	// 结束符(字节长度为2)
	byte[] end_byte = new byte[2];


	/**
	 * @Title: toByteArray
	 * @Description: 将IOTPBean转成byte[]
	 * @param @return    参数
	 * @return byte[]    返回类型
	 * @throws
	 */
	public List<byte[]> toByteArray(IOTPBean iotpBean){
		List<byte[]> iotp = new ArrayList<byte[]>();
		// 协议标签(字节长度为2)
		tag_byte = Hex.intToByteArrayDesc(iotpBean.getTag(), 2);
		// 命令类型(字节长度为2)
		type_byte = Hex.intToByteArrayDesc(iotpBean.getType(), 2);
		// 源ID号(字节长度为4)
		source_id_byte = Hex.intToByteArrayDesc(iotpBean.getSource_id(), 4);
		// 源类型号(字节长度为4)
		source_type_byte = Hex.intToByteArrayDesc(iotpBean.getSource_type(), 4);
		// 协议序列号(字节长度为4)
		sequence_id_byte = Hex.intToByteArrayDesc(iotpBean.getSequence_id(), 4);
		// 协议包生成时间(字节长度为8)
		date_time_byte = Hex.longToBytes(iotpBean.getDate_time().getTime());
		// 节点授权码(字节长度128)
		license_byte = Hex.stringToBytes(iotpBean.getLicense(), 128);//UTF-8编码
		// 结束符(字节长度为2)
		end_byte = Hex.intToByteArrayDesc(iotpBean.getEnd(), 2);
		
		// 协议消息体(转成json格式并加密后的长度最长为8192字节，长度将赋值给body_len)
		String bodyStr = JSON.toJSONString(iotpBean.getBody());
		//加密处理
		/*
		 * 加密算法还没有给，暂时将该步骤空余出来
		 */
		String encryptionStr = bodyStr;//encryption(bodyStr);//加密处理
//		System.out.println("--- --- --- --- --- --- --- "+encryptionStr);
		byte [] encryptionByteArray = null;
		try {
			encryptionByteArray = encryptionStr.getBytes("utf-8");
		} catch (UnsupportedEncodingException e) {
			encryptionByteArray = null;
		}
		if(encryptionByteArray != null && encryptionByteArray.length <= 8192){ // 单个消息体
			body_byte = encryptionByteArray;
			iotpBean.setBody_len(encryptionByteArray.length);
			iotpBean.setSequence_sub_id(0);
			// 协议体长度(字节长度为4)
			this.body_len_byte = Hex.intToByteArrayDesc(iotpBean.getBody_len(), 4);
			// 协议子序列号(字节长度为4)
			sequence_sub_id_byte = Hex.intToByteArrayDesc(iotpBean.getSequence_sub_id(), 4);
			// 定义协议消息
			byte[] iotpByteArray = new byte[162+iotpBean.getBody_len()];
			iotp.add(partEncapsulation(iotpByteArray,iotpBean.getBody_len()));// 调用整合方法并将返回值放到集合中
			return iotp;
		}else if(encryptionByteArray != null){ // 多个消息体
			int lengthOfBody = encryptionByteArray.length;// 消息体的总长度
			int part_index = 0;
//			System.out.println("-- -- -- -- -- -- -- -- -- "+lengthOfBody);
			iotpBean.setSequence_sub_id(1);
			iotpBean.setBody_len(8192);
			while(lengthOfBody > 0){
				body_byte = getNewByteArray(encryptionByteArray, (part_index * 8192), iotpBean.getBody_len());
				// 协议体长度(字节长度为4)
				body_len_byte = Hex.intToByteArrayDesc(iotpBean.getBody_len(), 4);
				// 协议子序列号(字节长度为4)
				sequence_sub_id_byte = Hex.intToByteArrayDesc(iotpBean.getSequence_sub_id(), 4);
				// iotp消息
				byte[] iotpByteArray = new byte[(162+iotpBean.getBody_len())];
				iotp.add(partEncapsulation(iotpByteArray,iotpBean.getBody_len()));// 调用整合方法并将返回值放到集合中
				lengthOfBody = lengthOfBody - 8192;
				iotpBean.setSequence_sub_id(lengthOfBody <= 8192 ? -1 : (iotpBean.getSequence_sub_id() + 1));
				iotpBean.setBody_len(lengthOfBody <= 8192 ? lengthOfBody : 8192);
				part_index++;
			}
			return iotp;
		}else{
			return null;
		}
	}
	
	/**
	 * @Title: byteArrayAddbyteArray
	 * @Description: 将byte数组b添加到byte数组a的下标为start到下标为（start+step-1）的位置上
	 * 	如果（start+step-1）超出了a的长度，则超出部分将丢弃。
	 *  如果start起始位置超出a的长度，则按取模数为下标起始位置
	 *  如果start起始位置是负数，则按0为下标起始位置
	 * @param @param a
	 * @param @param b
	 * @param @param start 下标起始位置
	 * @param @param step byte数组b在byte数组a中要占据的长度
	 * @param @return    参数
	 * @return void    返回类型
	 * @throws
	 */
	private void byteArrayAddbyteArray(byte[] a,byte[] b,int start,int step){
		start = start < 0 ? 0: (start > (a.length - 1) ? start % a.length : start);
		step = (start+step-1) > (a.length - 1) ? (a.length - 1) : (start+step-1);
		int index = 0;
		for(int i = start; i <= step; i++){
			a[i] = b[index];
			index++;
		}
	}
	
	/**
	 * @Title: partEncapsulation
	 * @Description: 将各部分整合
	 * @param @param iotpByteArray
	 * @param @param body_len
	 * @param @return    参数
	 * @return byte[]    返回类型
	 * @throws
	 */
	private byte[] partEncapsulation(byte[] iotpByteArray,Integer body_len){
		byteArrayAddbyteArray(iotpByteArray,tag_byte,0,2);// 协议标签(字节长度为2)
		byteArrayAddbyteArray(iotpByteArray,type_byte,2,2);// 命令类型(字节长度为2)
		byteArrayAddbyteArray(iotpByteArray,source_id_byte,4,4);// 源ID号(字节长度为4)
		byteArrayAddbyteArray(iotpByteArray,source_type_byte,8,4);// 源类型号(字节长度为4)
		byteArrayAddbyteArray(iotpByteArray,sequence_id_byte,12,4);// 协议序列号(字节长度为4)
		byteArrayAddbyteArray(iotpByteArray,sequence_sub_id_byte,16,4);// 协议子序列号(字节长度为4)
		byteArrayAddbyteArray(iotpByteArray,date_time_byte,20,8);// 协议包生成时间(字节长度为8)
		byteArrayAddbyteArray(iotpByteArray,license_byte,28,128);// 节点授权码(字节长度128)
		byteArrayAddbyteArray(iotpByteArray,body_len_byte,156,4);// 协议体长度(字节长度为4)
		byteArrayAddbyteArray(iotpByteArray,body_byte,160,body_len);// 协议消息体(字节长度为body_len)
		byteArrayAddbyteArray(iotpByteArray,end_byte,(160+body_len),2);// 结束符(字节长度为2)
		return iotpByteArray;
	}
	
	/********************************************************** 转成byte数组 **********************************************************/
}
